/*	Copyright 2008 Jacquemin Valentin

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
	
	@author pollux
 */
package org.poxd.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.metal.MetalLookAndFeel;

import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.jdesktop.layout.GroupLayout;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.painter.MattePainter;
import org.jdesktop.swingx.plaf.PainterUIResource;
import org.jdesktop.swingx.plaf.UIManagerExt;
import org.poxd.model.AllLanguages;
import org.poxd.model.Category;
import org.poxd.model.Language;
import org.poxd.model.Snippet;
import org.poxd.persistance.SessionService;
import org.poxd.tools.ConfigUtils;
import org.poxd.tools.LanguagesFileReader;

import actions.ActionManager;

/**
 * @author pollux
 * 
 */
public class MainPane extends JRootPane {
	private static final long serialVersionUID = 1L;
	private static final Logger log = Logger.getLogger(MainPane.class);
	private JSplitPane catAndSnips;
	private CategoriesPanel categoriesPanel;
	private CodePanel codePanel;
	private JFrame mainFrame;
	Language currentLanguage;
	private NewLanguageDialog newLanguageDialog;
	private NewCategoryDialog newCategoryDialog;
	private NewSnippetDialog newSnippetDialog;
	private final LanguagesPanel languageList;

	public enum ACTIONS {
		NEW_LANGUAGE, NEW_CATEGORY, NEW_SNIPPET
	};

	public MainPane(JFrame mainFrame) {
		this.mainFrame = mainFrame;
		JPanel content = new JPanel();
		content.setLayout(new BorderLayout());

		JPanel languageContent = new JPanel();
		languageList = new LanguagesPanel(this);
		languageList.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting() == false) {
					int index = languageList.getSelectedIndex();
					if (index >= 0) {
						setLanguage(languageList.getSelectedLanguage());
					}
				}
			}
		});
		UIManager.getLookAndFeelDefaults().put(JXTitledPanel.uiClassID,
				"org.jdesktop.swingx.plaf.basic.BasicTitledPanelUI");
		UIManager.getLookAndFeelDefaults().put(
				"JXTitledPanel.titleFont",
				UIManagerExt.getSafeFont("Button.font", new FontUIResource(
						"Dialog", Font.PLAIN, 12)));
		UIManager.getLookAndFeelDefaults().put("JXTitledPanel.titleForeground",
				new ColorUIResource(Color.WHITE));
		UIManager
				.getLookAndFeelDefaults()
				.put(
						"JXTitledPanel.titlePainter",
						new PainterUIResource(
								new MattePainter<GradientPaint>(
										new GradientPaint(
												0,
												0,
												MetalLookAndFeel
														.getCurrentTheme()
														.getPrimaryControl(),
												0,
												1,
												MetalLookAndFeel
														.getCurrentTheme()
														.getPrimaryControlDarkShadow()),
										true)));
		UIManager.getLookAndFeelDefaults().put("JXTitledPanel.captionInsets",
				new InsetsUIResource(4, 12, 4, 12));
		UIManager.getLookAndFeelDefaults().put(
				"JXTitledPanel.rightDecorationInsets",
				new InsetsUIResource(1, 1, 1, 1));
		UIManager.getLookAndFeelDefaults().put(
				"JXTitledPanel.leftDecorationInsets",
				new InsetsUIResource(1, 1, 1, 1));
		JXTitledPanel languagePane = new JXTitledPanel("Languages",
				languageList);
		languageContent.setLayout(new BoxLayout(languageContent,
				BoxLayout.X_AXIS));
		languageContent.add(languagePane);
		languageContent.add(Box.createHorizontalStrut(3));
		double maxHeight = languagePane.getMaximumSize().getHeight();
		languagePane.setMaximumSize(new Dimension((int) languageList
				.getMaximumSize().getWidth(), (int) maxHeight));

		categoriesPanel = new CategoriesPanel(this);
		JXTitledPanel categoriesPane = new JXTitledPanel("Categories",
				categoriesPanel);
		codePanel = new CodePanel();
		catAndSnips = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
				categoriesPane, codePanel);
		catAndSnips.setBorder(null);
		catAndSnips.setResizeWeight(0.4);

		content.add(languageContent, BorderLayout.WEST);
		content.add(catAndSnips);
		// add(getToolBar(), BorderLayout.NORTH);

		addListeners();
		initActions();
		setContentPane(content);
	}

	private void addListeners() {
		mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		mainFrame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				exit();
			}

		});
	}

	public void initActions() {
		try {
			URL xml = MainPane.class
					.getResource("/org/poxd/ui/actions/actions.xml");
			ResourceBundle bundle = new PropertyResourceBundle(
					MainPane.class
							.getResourceAsStream("/org/poxd/ui/actions/actions.properties"));
			ActionManager am = ActionManager.createActionManager(xml, this,
					bundle);

			// Get a menu bar from ActionManager
			JMenuBar menu = am.createMenuBar();

			am.bindKeys(this);
			menu.setBorderPainted(false);
			setJMenuBar(menu);
		} catch (IOException e) {
			log.log(Priority.WARN, e);
		}
	}

	// private JToolBar getToolBar() {
	// JToolBar tb = new JToolBar();
	// tb.add(getActionMap().get(ACTIONS.NEW_LANGUAGE));
	// tb.add(getActionMap().get(ACTIONS.NEW_CATEGORY));
	// tb.add(getActionMap().get(ACTIONS.NEW_SNIPPET));
	// tb.setFloatable(false);
	// tb.setBorder(BorderFactory.createEmptyBorder(1, 0, 3, 0));
	// tb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
	// return tb;
	// }

	void saveModel() {
		List<Language> model = languageList.getModel();
		Session s = SessionService.getSession();
		s.beginTransaction();
		for (Language l : model) {
			s.saveOrUpdate(l);
		}
		s.flush();
		s.getTransaction().commit();
		try {
			s.connection().createStatement().execute("COMMIT;");
		} catch (HibernateException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		log.debug("SAVE MODEL COMMITED");
	}

	void setLanguage(Language l) {
		log.debug("CURRENT LANGUAGE " + l);
		getActionMap().get("newCategory").setEnabled(true);
		// getActionMap().get(ACTIONS.NEW_SNIPPET).setEnabled(true);
		currentLanguage = l;
		categoriesPanel.setSelectedLanguage(l);
		codePanel.setSnippet(null);
	}

	void setSnippet(Snippet s) {
		codePanel.setSnippet(s);
	}

	void exit() {
		saveModel();
		try {
			SessionService.getSession().connection().createStatement().execute(
					"SHUTDOWN;");
		} catch (HibernateException e1) {
			e1.printStackTrace();
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		SessionService.closeSession();
		System.exit(0);
	}

	void newLanguage() {
		newLanguageDialog = new NewLanguageDialog(mainFrame);
		newLanguageDialog.pack();
		newLanguageDialog.setLocationRelativeTo(mainFrame);
		newLanguageDialog.setVisible(true);
	}

	public void newCategory() {
		newCategoryDialog = new NewCategoryDialog(mainFrame);
		newCategoryDialog.init();
		newCategoryDialog.pack();
		newCategoryDialog.setLocationRelativeTo(mainFrame);
		newCategoryDialog.setVisible(true);
	}

	public void newSnippet() {
		newSnippetDialog = new NewSnippetDialog(mainFrame);
		newSnippetDialog.pack();
		newSnippetDialog.setLocationRelativeTo(mainFrame);
		newSnippetDialog.setVisible(true);
	}

	public void editSnippet(Snippet snippet) {
		EditSnippetDialog editSnippetDialog = new EditSnippetDialog(mainFrame,
				snippet);
		editSnippetDialog.pack();
		editSnippetDialog.setLocationRelativeTo(mainFrame);
		editSnippetDialog.setVisible(true);
	}

	public void removeCategory(Category selected) {
		currentLanguage.getCategories().remove(selected.getName());
	}

	private class NewLanguageDialog extends JDialog {
		private static final long serialVersionUID = 1L;
		private final JList languages;
		private final JButton ok;
		private final JButton cancel;

		public NewLanguageDialog(JFrame frame) {
			super(frame, true);
			JPanel content = new JPanel();
			content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));

			JPanel list = new JPanel();
			languages = new JList();
			languages.setCellRenderer(new LanguageCellRenderer());
			languages.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			languages.setLayoutOrientation(JList.HORIZONTAL_WRAP);
			languages.setVisibleRowCount(2);
			languages.setFixedCellHeight(55);
			languages.setFixedCellWidth(50);
			languages.setBackground(Color.WHITE);
			// TODO remove languages that are already in the list
			AllLanguages model = new LanguagesFileReader(
					ConfigUtils.SNIWE_PROPERTIES_PATH);
			languages.setModel(model);
			list.add(new JScrollPane(languages));

			JPanel controls = new JPanel();
			ok = new JButton("Ok");
			ActionListener al = new NewLanguageListener();
			ok.addActionListener(al);
			cancel = new JButton("Cancel");
			cancel.addActionListener(al);
			controls.add(ok);
			controls.add(cancel);

			content.add(list);
			content.add(Box.createVerticalStrut(3));
			content.add(controls);

			setContentPane(content);
			setResizable(false);
		}

		private class NewLanguageListener implements ActionListener {
			public void actionPerformed(ActionEvent e) {
				Object source = e.getSource();
				if (source == ok) {
					final Language selected = (Language) languages
							.getSelectedValue();
					new Thread(new Runnable() {
						public void run() {
							Category nc = categoriesPanel.getNewCategory("");
							Map<String, Category> cats = new HashMap<String, Category>();
							cats.put("", nc);
							selected.setCategories(cats);
							languageList.addLanguage(selected);
							setLanguage(selected);
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									NewLanguageDialog.this.dispose();
									newLanguageDialog = null;
								}
							});
						}
					}).start();
					NewLanguageDialog.this.setEnabled(false);
				} else if (source == cancel) {
					NewLanguageDialog.this.dispose();
					newLanguageDialog = null;
				}
			}
		}
	}

	private class NewCategoryDialog extends JDialog {
		private static final long serialVersionUID = 1L;
		private final JTextField category;
		private final JButton add;

		public NewCategoryDialog(JFrame frame) {
			super(frame, true);
			JPanel content = new JPanel();
			JLabel title = new JLabel("Titre :");
			category = new JTextField(20) {
				private static final long serialVersionUID = 1L;

				@Override
				protected void processKeyEvent(KeyEvent e) {
					if (e.getKeyChar() == KeyEvent.VK_ENTER) {
						add.doClick();
						e.consume();
					}
					super.processKeyEvent(e);
				}
			};
			title.setLabelFor(category);
			add = new JButton("Ajouter");
			content.add(title);
			content.add(category);
			content.add(add);

			setContentPane(content);
			setResizable(false);

			add.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					final String title = category.getText();
					newCategoryDialog.setEnabled(false);
					// TODO change priority
					new Thread(new Runnable() {
						public void run() {
							Category newCat = categoriesPanel
									.getNewCategory(title);
							currentLanguage.getCategories().put(
									newCat.getName(), newCat);
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									newCategoryDialog.dispose();
									newCategoryDialog = null;
									categoriesPanel
											.setSelectedLanguage(currentLanguage);
								}
							});
						}
					}).start();
				}
			});
		}

		void init() {
			category.setText("");
			category.requestFocus();
		}
	}

	private class NewSnippetDialog extends JDialog {
		private static final long serialVersionUID = 1L;
		protected final JButton okButton;
		protected final JButton cancelButton;
		protected final JTextField titleValue;
		protected final JTextArea descriptionValue;
		protected final SniweTextArea snippetCode;
		protected Snippet snippet;

		public NewSnippetDialog(JFrame frame) {
			super(frame, true);
			snippet = new Snippet();
			JPanel content = new JPanel();
			JPanel controlsPanel = new JPanel();

			JLabel t = new JLabel("Titre");
			t.setHorizontalAlignment(JLabel.RIGHT);
			t.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
			titleValue = new JTextField(20);
			t.setLabelFor(titleValue);

			JLabel d = new JLabel("Description");
			d.setVerticalAlignment(JLabel.TOP);
			d.setHorizontalAlignment(JLabel.RIGHT);
			d.setBorder(BorderFactory.createEmptyBorder(1, 3, 0, 3));
			descriptionValue = new JTextArea(10, 80);
			descriptionValue.setLineWrap(true);
			descriptionValue.setWrapStyleWord(true);
			// descriptionValue.setBorder(titleValue.getBorder());

			JLabel s = new JLabel("Code");
			s.setVerticalAlignment(JLabel.TOP);
			s.setHorizontalAlignment(JLabel.RIGHT);
			s.setBorder(BorderFactory.createEmptyBorder(1, 3, 0, 3));

			snippetCode = new SniweTextArea();
			snippetCode.setBorder(titleValue.getBorder());
			snippetCode.setMarker(currentLanguage.getMarker());
			snippetCode.getPainter().setInvalidLinesPainted(false);

			okButton = new JButton("Ok");
			cancelButton = new JButton("Annuler");
			controlsPanel.add(okButton);
			controlsPanel.add(cancelButton);

			JScrollPane sDescValue = new JScrollPane(descriptionValue);

			GroupLayout layout = new GroupLayout(content);
			content.setLayout(layout);
			layout.setAutocreateGaps(true);
			layout.setAutocreateContainerGaps(true);
			GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
			hGroup.add(
					layout.createParallelGroup(GroupLayout.TRAILING).add(t)
							.add(d).add(s)).add(
					layout.createParallelGroup().add(titleValue)
							.add(sDescValue).add(snippetCode));
			layout.setHorizontalGroup(hGroup);
			GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
			vGroup.add(
					layout.createParallelGroup(GroupLayout.BASELINE).add(t)
							.add(titleValue)).add(
					layout.createParallelGroup(GroupLayout.BASELINE).add(d)
							.add(sDescValue)).add(
					layout.createParallelGroup(GroupLayout.BASELINE).add(s)
							.add(snippetCode));
			layout.setVerticalGroup(vGroup);

			JPanel c = new JPanel();
			c.setLayout(new BorderLayout());
			c.add(content);
			c.add(controlsPanel, BorderLayout.SOUTH);
			setContentPane(c);
			setResizable(false);

			okButton.addActionListener(new SnippetDialogActionListener());
			cancelButton.addActionListener(new SnippetDialogActionListener());
		}

		protected class SnippetDialogActionListener implements ActionListener {
			public void actionPerformed(ActionEvent e) {
				Object source = e.getSource();
				if (source == cancelButton) {
					NewSnippetDialog.this.dispose();
					newSnippetDialog = null;
				} else if (source == okButton) {
					NewSnippetDialog.this.setEnabled(false);
					new Thread(new Runnable() {
						public void run() {
							String title = titleValue.getText();
							String desc = descriptionValue.getText();
							String content = snippetCode.getText();
							// TODO TEST VALUES
							snippet.setTitle(title);
							snippet.setDescription(desc);
							snippet.setCode(content);
							categoriesPanel.addSnippet(snippet);
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									NewSnippetDialog.this.dispose();
									newSnippetDialog = null;
									setLanguage(currentLanguage);
								}
							});
						}
					}).start();
				}
			}
		}
	}

	private class EditSnippetDialog extends NewSnippetDialog {
		private static final long serialVersionUID = 1L;

		public EditSnippetDialog(JFrame frame, final Snippet snippet) {
			super(frame);
			this.snippet = snippet;
			titleValue.setText(snippet.getTitle());
			descriptionValue.setText(snippet.getDescription());
			snippetCode.setText(snippet.getCode());
			snippetCode.scrollTo(0, 0);
			okButton.removeActionListener(okButton.getActionListeners()[0]);
			okButton.addActionListener(new SnippetDialogActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					EditSnippetDialog.this.snippet.setId(snippet.getId());
					super.actionPerformed(e);
				}
			});
		}
	}
}
